import configparser
import re
import yaml
from openpyxl import load_workbook
import os

PROJECT_NAME = 'auto_interface'
CUR_DIR = os.path.abspath(__file__)
project_path_index = CUR_DIR.index(PROJECT_NAME) + len(PROJECT_NAME)
PROJECT_DIR = CUR_DIR[:project_path_index]
INI_DIR = os.path.join(PROJECT_DIR, 'pytest.ini')


def read_excel(file, sheet_name=None):
    """ 读取excel，并以tuple格式返回所有数据行(不包括标题行) """
    #  通过文件得到一个工作簿，参数是文件名，如果有路径，要填绝对路径
    wb = load_workbook(file)
    if not sheet_name:
        # 获取第一个sheet
        sheet = wb.active
    else:
        # 获取对应sheet
        sheet = wb[sheet_name]
    # 得到所有的数据
    tmp_rows = list(sheet.values)
    # 处理每一行数据
    rows = process_rows(tmp_rows)
    rows = [tuple(row) for row in rows[1:]]
    return rows


def read_excel_with_sheetname(file, sheet_name=None):
    """
    读取excel，并以dict格式返回，如{sheet名：[{'列标题': '列值'}]}
    sheet表去空，数据列前后去空格、空字符串用None代替
    """
    #  通过文件得到一个工作簿，参数是文件名，如果有路径，要填绝对路径
    wb = load_workbook(file)
    data = []
    if sheet_name:
        # 读取指定sheet内容
        sheets = [wb[sheet_name]]
    else:
        # 读取所有sheet
        sheets = wb.worksheets
    for sheet in sheets:
        # 得到所有的数据
        tmp_rows = list(sheet.values)
        # 若为空sheet，退出本次循环
        if not tmp_rows:
            continue
        # 处理每一行数据
        rows = process_rows(tmp_rows)
        titles = rows[0]
        # 标题行和数据行组合后转为字典,key为标题，value为数据列
        content = [dict(zip(titles, row)) for row in rows[1:]]
        data.append({sheet.title: content})
    return data


def read_excel_without_sheetname(file, sheet_name=None):
    """ 读取excel，并以dict格式返回所有标题+数据 """
    #  通过文件得到一个工作簿，参数是文件名，如果有路径，要填绝对路径
    wb = load_workbook(file)
    if not sheet_name:
        # 获取第一个sheet
        sheet = wb.active
    else:
        # 获取对应sheet
        sheet = wb[sheet_name]
    # 得到所有的数据(去除前后空格)
    tmp_rows = list(sheet.values)
    # 处理每一行数据
    rows = process_rows(tmp_rows)
    titles = rows[0]
    # 标题行和数据行组合后转为字典,key为标题，value为数据列
    data = [dict(zip(titles, row)) for row in rows[1:]]
    return data


def read_cases_from_excel(file, sheet_name=None):
    """
    读取excel，没传sheet_name，则读取第一个sheet内容
    以list格式返回，如[(sheet名, {'列标题': '列值'})],每一行都带上sheet名
    前后去空格、空字符串用None代替
    """
    #  通过文件得到一个工作簿，参数是文件名，如果有路径，要填绝对路径
    wb = load_workbook(file)
    if not sheet_name:
        # 获取第一个sheet
        sheet = wb.active
        # 获取第一个sheetname
        sheet_name = wb.sheetnames[0]
    sheet = wb[sheet_name]
    # 得到所有的数据
    tmp_rows = list(sheet.values)
    if not tmp_rows:
        raise ValueError(f'sheet表:{sheet_name}内容为空！')
    # 处理每一行数据
    rows = process_rows(tmp_rows)
    titles = rows[0]
    # 标题行和数据行组合后转为字典,key为标题，value为数据列
    content = [dict(zip(titles, row)) for row in rows[1:]]
    data = [(sheet_name, row) for row in content]
    return data


def read_yaml(file):
    with open(file, mode='r', encoding='utf-8') as f:
        data = yaml.load(f, Loader=yaml.FullLoader)
    return data


def read_ini(config_file=INI_DIR):
    """ 读取ini配置文件 """
    conf = configparser.ConfigParser()
    conf.read(config_file, encoding='utf-8')
    return conf


def is_contain(sup_dict, sub_dict):
    """ 判断父字典sup_dict是否包含子字典sub_dict """
    sup_set = set(sup_dict.items())
    sub_set = set(sub_dict.items())
    return sub_set.issubset(sup_set)


def is_condition(condition, row):
    """
    判断字典是否满足条件
    :param condition:条件,同sql语句条件
    :param row:字典
    :return:布尔值
    """
    # flag = False
    condition = str(condition).strip()
    # 处理 id > 5 and/or id < 10的情况
    split_condition = re.split(r'(and|or)', str(condition).strip())
    split_condition.insert(0, 'or')
    link_list = split_condition[::2]
    condition_list = split_condition[1::2]
    condition_link_list = list(zip(link_list, condition_list))
    return assert_result(condition_link_list, row)


def assert_result(condition_link_list, row):
    flag = True
    for condition_link in condition_link_list:
        condition = condition_link[1]
        link_mark = condition_link[0]
        # 匹配操作符
        pattern = r'(.+)([><]=?|\s+=|==|\bin)(.+)'
        matcher = re.match(pattern, condition)
        if not matcher:
            raise ValueError(f'条件:{condition}格式不正确！')
        split_result = [str(i).strip() for i in matcher.groups()]
        condition_column = split_result[0]
        condition_type = split_result[1]
        condition_value = split_result[2]
        condition_type = '==' if condition_type == '=' else condition_type
        # 按sql语句的格式填写,如 column in ('数据1','数据2')
        if condition_type == 'in':
            # 把(a,b)格式的字符串修改为(a,b,),因为只有1个元素时eval((a))报错
            condition_value = condition_value[:-1] + ',' + condition_value[-1]
            condition_value = tuple(eval(condition_value))
            new_flag = row[condition_column] in condition_value
        else:
            expression = str(row[condition_column]) + ' ' + condition_type + ' ' + condition_value
            new_flag = True if eval(expression) else False
        if link_mark == 'and' and not (new_flag and flag):
            flag = False
            break
        flag = new_flag
    return flag


def get_table_and_rows(excel, *, sheet_name=None, condition=None, include_column=None, exclude_column=None):
    """
    获取excel中sheet名和当前sheet的数据
    :param excel:excel中所有表名+数据行的字典
    :param sheet_name:sheet名
    :param condition:可以为dict或str，dict类型条件如:{'id': 10},str类型条件同sql语句格式,如:id = 10或id in (10)
    :param include_column:只获取需要的列
    :param exclude_column:排除不需要的列
    :return:表名+数据行的tuple
    """
    table_name, rows = None, None
    if sheet_name:
        for table in excel:
            for k, v in table.items():
                if sheet_name == k:
                    table_name, rows = k, v
                    break
    else:
        # 获取第一个sheet的信息
        table_name = list(excel[0].items())[0][0]
        rows = list(excel[0].items())[0][1]
    if isinstance(condition, dict):
        # 根据条件筛选满足的数据行
        rows = list(filter(lambda row: is_contain(row, condition), rows))
    elif isinstance(condition, str):
        # 根据条件筛选满足的数据行
        rows = list(filter(lambda row: is_condition(condition, row), rows))
    if exclude_column:
        # 排除不需要的列
        rows = [dict(filter(lambda item: item[0] not in exclude_column, row.items())) for row in rows]
    if include_column:
        # 只获取需要的列
        rows = [dict(filter(lambda item: item[0] in include_column, row.items())) for row in rows]
    return table_name, rows


def process_rows(rows):
    # 数据列去空格
    rows = list(map(lambda row: rm_space(row), rows))
    # 获取所有的非空标题
    rows[0] = [column for column in rows[0] if column]
    return rows


def rm_space(row):
    """ 去除list每个元素前后空格，用None替换空字符串 """
    # 数据列前后去空格
    tmp_rows = map(lambda column: column if not isinstance(column, str) else column.strip(), row)
    # 用None替换空字符串
    row = list(map(lambda column: column if column else None, tmp_rows))
    return row


if __name__ == '__main__':
    # excel_dir = r'/test_data/rabbit_platform/test_case.xlsx'
    # none_excel_dir = r'/test_data/rabbit_platform/空excel.xlsx'
    # data = read_cases_from_excel(excel_dir, 'query_api_list')
    # read_excel_with_sheetname
    # data1 = read_excel_without_sheetname(excel_dir, 'query_api_list')
    # data2 = read_excel_with_sheetname(excel_dir, 'query_api_list')
    # data3 = read_excel(excel_dir, 'query_api_list')
    # print(f'read_cases_from_excel={data}\n'
    #       f'read_excel_without_sheetname={data1}\n'
    #       f'read_excel_with_sheetname={data2}\n'
    #       f'read_excel={data3}\n')

    # print(read_ini().get('pytest', 'markers'))
    xiaoming = {'name': 'xiaoming', 'age': 18}
    name = {'name': 'xiaoming'}
    # print(is_contain(xiaoming, name))
    print(is_condition("age > 10 or age < 20", xiaoming))
    # print(10 in (10, 9))
    # print(eval('(1,2,)'))
    # print('good'[:-1] + ',' + 'good'[-1])
    # str_condition = 'age >= 18'
    # pattern = r'(.+)([><]=?|\s+=|\bin)(.+)'
    # matcher = re.match(pattern, str_condition)
    # print(matcher.groups() if matcher else None)
    # print(is_condition(str_condition, xiaoming))
    # print(eval('"name" in {"name":"xiaowang"}'))
    # print('name' in xiaoming)
    # 保留分隔符
    # print(re.split('(,|in)', '我是,真的in   house'))
